/**
 * @author Escallier Pierre
 * @file EPFctPart.java
 * @date 6 sept. 2008
 */
package epsofts.utils;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 
 */
public class EPFctPart
{
	private static void tryToGetResource(String resource)
	{
		System.out.println("[" + resource + "] " + ClassLoader.getSystemResource(resource));
	}

	/**
	 * Retourne la liste des classes d�riv�es de la classe m�re donn�e.
	 * 
	 * @param i_package
	 *            Package a partir duquel se fait la recherche.
	 * @param i_classe
	 *            Classe m�re de laquelle on cherche les filles.
	 * @return String[] Noms des classes impl�mentants la classe m�re donn�e.
	 * @throws IOException
	 * @throws IOException
	 */
	/*
	 * public static <T> Class<? extends T>[] GetImplementationsClasses(final String i_package, final Class<T> i_classe) throws IOException { tryToGetResource(i_package);
	 * 
	 * URL url = ClassLoader.getSystemResource(i_package);
	 * 
	 * return GetImplementationsClasses(url, i_classe, i_package, null).toArray(new Class[0]); }
	 */

	private static <T> List<Class<? extends T>> GetImplementationsClasses(List<String> classFiles, Class<T> i_classe) throws IOException
	{
		List<Class<? extends T>> classes = new Vector<Class<? extends T>>();

		for (String s : classFiles)
		{
			Class<?> c = null;
			try
			{
				c = ClassLoader.getSystemClassLoader().loadClass(s);
				if (i_classe.isAssignableFrom(c) && (i_classe != c))
				{
					classes.add((Class<? extends T>) c);
				}
			}
			catch (ClassNotFoundException e)
			{
				throw new IOException("Exception dans la r�cup�ration dynamique de classe : " + e);
			}
		}

		return classes;
	}

	public static <T> List<Class<? extends T>> GetImplementationsClasses(final String i_package, final Class<T> i_classe) throws IOException
	{

		List<Class<? extends T>> classes = new Vector<Class<? extends T>>();

		URL packageURL = ClassLoader.getSystemResource(i_package);

		if (packageURL == null) return classes;

		List<String> classesPath = new Vector<String>();

		if (packageURL.getProtocol().compareToIgnoreCase("jar") == 0)
		{
			JarFile jar = ((JarURLConnection) packageURL.openConnection()).getJarFile();

			JarEntry packageEntry = jar.getJarEntry(i_package);
			if (packageEntry == null) return classes;

			Enumeration<JarEntry> entries = jar.entries();
			while (entries.hasMoreElements())
			{
				JarEntry entry = entries.nextElement();

				String name = entry.getName();

				if ( !entry.isDirectory() && name.startsWith(packageEntry.getName()) && name.endsWith(".class") && name.indexOf('$') < 0)
				{
					// accept
					name = name.substring(0, name.length() - 6);
					name = name.substring(packageEntry.getName().length() - i_package.length(), name.length()).replaceAll("/", ".").replaceAll("\\\\", ".");

					classesPath.add(name);
				}
			}

			if (classesPath.size() > 0)
			{
				classes.addAll(GetImplementationsClasses(classesPath, i_classe));
			}
		}
		else if (packageURL.getProtocol().compareToIgnoreCase("file") == 0)
		{
			File dir = new File(packageURL.getFile());

			File[] allFiles = dir.listFiles(new FileFilter()
			{
				public boolean accept(File i_pathname)
				{
					return (i_pathname.isFile() && i_pathname.getName().endsWith(".class") && i_pathname.getName().indexOf('$') < 0);
				}
			});

			for (File f : allFiles)
			{
				String s = f.toString();
				s = s.substring(0, s.length() - 6);
				s = s.substring(dir.getAbsolutePath().length() - i_package.length(), s.length()).replaceAll("/", ".").replaceAll("\\\\", ".");
				// s = s.substring(dir.getAbsolutePath().length() - sNouveauParentPackage.length(), s.length()).replaceAll("/", ".").replaceAll("\\\\", ".");
				classesPath.add(s);
			}

			if (classesPath.size() > 0)
			{
				classes.addAll(GetImplementationsClasses(classesPath, i_classe));
			}

			File[] allDirectories = dir.listFiles(new FileFilter()
			{
				public boolean accept(File i_pathname)
				{
					return i_pathname.isDirectory();
				}
			});

			for (File d : allDirectories)
			{
				classes.addAll(GetImplementationsClasses(i_package + "/" + d.getName(), i_classe));
			}
		}

		/*
		 * String sNouveauParentPackage = ""; if ((i_parentPackage != null) && (i_parentPackage.length() > 0)) { sNouveauParentPackage = i_parentPackage + "."; }
		 * 
		 * sNouveauParentPackage = sNouveauParentPackage + i_directory.getName();
		 * 
		 * String s = null; for (int i = 0; i < allFiles.length; ++i) { s = allFiles[i].toString(); s = s.substring(0, s.length() - 6); s = s.substring(i_directory.getAbsolutePath().length() - sNouveauParentPackage.length(), s.length()).replaceAll("/", ".").replaceAll("\\\\", "."); Class<?> c = null; try { c = ClassLoader.getSystemClassLoader().loadClass(s); if (i_classe.isAssignableFrom(c) && (i_classe != c)) { classes.add((Class<? extends T>) c); } } catch (ClassNotFoundException e) { throw new IOException("Exception dans la r�cup�ration dynamique de classe : " + e); } // s.substring(path.getAbsolutePath().length() - pack.length(), s.length()).replaceAll("/", "."); }
		 * 
		 * File[] allDirectories = i_directory.listFiles(new FileFilter() { public boolean accept(File i_pathname) { return i_pathname.isDirectory(); } });
		 * 
		 * for (int i = 0; i < allDirectories.length; ++i) { classes.addAll(GetImplementationsClasses(allDirectories[i], i_classe, i_package, sNouveauParentPackage)); }
		 */

		return classes;
	}
}
